/**
 * Copyright 2007-2008. Chongqing First Information & Network Co., Ltd. All
 * rights reserved. <a>http://www.cqfirst.com.cn</a>
 */
package com.cqcis.uip.base.framework.core.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.springframework.osgi.context.BundleContextAware;
import org.springframework.osgi.extender.internal.dependencies.startup.ContextState;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.base.adaptor.AbstractRegisteredService;
import com.cqcis.uip.base.framework.common.OperatorLog;
import com.cqcis.uip.base.framework.core.Endpoint;
import com.cqcis.uip.base.framework.core.LogService;
import com.cqcis.uip.base.framework.core.RegisteredService;
import com.cqcis.uip.base.framework.core.RegisteredServiceEvent;
import com.cqcis.uip.base.framework.core.RegisteredServiceEventType;
import com.cqcis.uip.base.framework.core.RegisteredServiceFindService;
import com.cqcis.uip.base.framework.core.RegisteredServiceListener;
import com.cqcis.uip.base.framework.core.RegisteredServiceRepository;
import com.cqcis.uip.base.framework.core.ServiceState;
import com.cqcis.uip.base.framework.core.StateManage;
import com.cqcis.uip.base.framework.core.channel.Channel;
import com.cqcis.uip.base.framework.utils.StringUtil;
import com.cqcis.uip.base.framework.utils.TimeUtil;
import com.cqcis.uip.base.logadaptor.LogConfiguration;

/**
 * @author huangmy
 * @date   2007-12-11
 */
public class InterfaceServiceTrackerCustomizerImpl 
   implements ServiceTrackerCustomizer, RegisteredServiceRepository, 
              BundleContextAware, RegisteredServiceFindService {
	private static Log log = LogFactory.getLog(InterfaceServiceTrackerCustomizerImpl.class);	
    private Map<String, Map<Endpoint, RegisteredService>> services = new ConcurrentHashMap<String, Map<Endpoint, RegisteredService>>();
	private BundleContext context; // BUNDLE上下文
	private ServiceTracker intfServiceTracker; // 服务发现	
	private ServiceRegistration rsFindServiceRegistration; // 服务查找
	private RegisteredServiceContextImpl registeredServiceContext; // 注册服务上下文实现	
	private LogService logService; /*日志服务*/	
	private Channel channel;   // 通道
	private LogConfiguration operatorLogConfig; // 操作日志配置
	private StateManage stateManage; // 服务状态管理
	private Map<RegisteredService, Collection<RegisteredServiceListener>> allRSListeners = new ConcurrentHashMap<RegisteredService, Collection<RegisteredServiceListener>>();
	
	public Channel getChannel() {
		return this.channel;
	}
	
	private class RSBundleListener implements SynchronousBundleListener {
		public void bundleChanged(BundleEvent event) {
			if (context != null && context.getBundle().getBundleId() == event.getBundle().getBundleId()) {
				switch (event.getType()) {				
				case BundleEvent.STOPPING: {				
					Collection<RegisteredService> rss = getRegisteredServices();
					if (rss != null) {
						// stop all rs
						for (Iterator<RegisteredService> it = rss.iterator(); it.hasNext();) {
							RegisteredService rs = it.next();
							
							stopRegisterService(rs);
						}
					}
					
					break;
				}
				default:
					break;
				}
			}
		}
	}
	
	/**
	 *  启动
	 */
	public void start() {
		operatorLogConfig = new LogConfiguration("operator-log", "INFO", "%d{HH:mm:ss}|%-5p|%m%n");
		context.addBundleListener(new RSBundleListener());
		
        registeredServiceContext = new RegisteredServiceContextImpl(channel, this, logService, 
        		null, this.allRSListeners, this.context);	
		
		try {
			registeredServiceContext.start();
		} catch (Exception e) {			
			throw new RuntimeException("RegisteredServiceContext start exception.", e);
		}
		
		ServiceReference ssmRf = context.getServiceReference(StateManage.class.getName());
        if (ssmRf != null) {
        	this.stateManage = (StateManage) context.getService(ssmRf);
        }
        
        rsFindServiceRegistration = context.registerService(RegisteredServiceFindService.class.getName(), this, null);
        
        intfServiceTracker = new ServiceTracker(context, 
				RegisteredService.class.getName(), 
	             this);
		intfServiceTracker.open(true);
	}
	
	/**
	 * 停止
	 */
	public void stop() {
		if (intfServiceTracker != null) {
			intfServiceTracker.close();
		}
		
		if (services != null) {
			services.clear();
		}
		
		if (registeredServiceContext != null) {
			try {
				registeredServiceContext.stop();
			} catch (Exception e) {
				log.info("RegisteredServiceContext stop exception.", e);
			}
		}
		
		if (rsFindServiceRegistration != null) {
			rsFindServiceRegistration.unregister();
		}
	}
	
	public Object addingService(ServiceReference reference) {
		Object service = context.getService(reference);
		
		if (service instanceof RegisteredService) {
			RegisteredService registeredService = (RegisteredService)service;
			long bundleId = registeredService.getBundleContext().getBundle().getBundleId();
			
			ServiceState sstate = this.stateManage.getState(bundleId);
			if (sstate != null && (service instanceof AbstractRegisteredService)) {
				((AbstractRegisteredService)service).registerClassLoader(sstate.getClassLoader());
			}
			
			// 先判断状态是否已经是Started
			this.stateManage.waitWithStartedState(bundleId, 10 * 1000);
			
			this.stateManage.updateState(bundleId, 
					ContextState.RESOLVING_DEPENDENCIES, "RegisteredService Starting", null);
			
			// 通知各Listener;正在启动
			fireServiceEvent(registeredService, RegisteredServiceEventType.STARTING);
			
			try {
				startRegisterService(registeredService);
			} catch (Throwable e) {
				this.stateManage.updateState(bundleId, 
						ContextState.INTERRUPTED, "Start RegisteredService Exception: " + registeredService, e);
				return registeredService;
			}
			
			this.stateManage.updateState(bundleId, 
					ContextState.STARTED, "RegisteredService Started", null);
						
			// 启动时间
			registeredService.getAttributes().setAttribute(FrameworkConstants.RS_ATTR_STARTTIME, TimeUtil.getCurrentTime());
			
			// 文件操作日志 operator-log
			startRSOperatorLog(registeredService);
			
			// 启动
			fireServiceEvent(registeredService, RegisteredServiceEventType.STARTED);
		}
		
		return service;
	}

	public void modifiedService(ServiceReference reference, Object service) {		
	}

	public void removedService(ServiceReference reference, Object service) {
        Object serviceObject = context.getService(reference);
        
		if (serviceObject instanceof RegisteredService) {
			RegisteredService registeredService = (RegisteredService)serviceObject;
			
			// 正在停止
			fireServiceEvent(registeredService, RegisteredServiceEventType.STOPPING);
						
			// stop it
			stopRegisterService(registeredService);
			
			// 文件操作日志 operator-log
			stopRSOperatorLog(registeredService);
			
			// 停止
			fireServiceEvent(registeredService, RegisteredServiceEventType.STOPPED);
		}
	}
	
	/**
	 * 发布事件
	 * 
	 * @param rs
	 * @param state
	 */
	private void fireServiceEvent(RegisteredService rs, RegisteredServiceEventType state) {
		RegisteredServiceEvent event = new RegisteredServiceEvent(state, rs);		
		for (Entry<RegisteredService, Collection<RegisteredServiceListener>> entry : this.allRSListeners.entrySet()) {				
			RegisteredService service = entry.getKey();
			if (rs == service) {
				continue;// 不发布给本身
			}
			
			List<LogConfiguration> oldLogConfigr = null;
			
			try {
				oldLogConfigr = logService.getLogConfiguration(Thread
						.currentThread());
				logService.unregister(Thread.currentThread());
				logService.register(service.getLogConfiguration());

				Collection<RegisteredServiceListener> listeners = entry
						.getValue();
				for (RegisteredServiceListener l : listeners) {
					try {
						l.seviceChanged(event);
					} catch (Throwable t) {
						log.error(
								"Catch Exception in notify event listeners. state = "
										+ state + ", RS = " + rs, t);
					}
				}
			} finally {
				if (oldLogConfigr != null) {
					logService.unregister();
					for (LogConfiguration config : oldLogConfigr) {
						logService.register(config);
					}
				} else {
					logService.unregister();
				}
			}
		}
	}
	
	/**
	 * 服务描述
	 * 
	 * @param registeredService
	 * @return
	 */
	private String createRSOperatorStr(RegisteredService registeredService) {
		StringBuffer buffer = new StringBuffer(64);
		buffer.append("[").append(registeredService).append("]");
		return buffer.toString();
	}
	
	/**
	 * 服务启动操作日志
	 * 
	 * @param registeredService
	 */
	private void startRSOperatorLog(RegisteredService registeredService) {
		List<LogConfiguration> oldLogConfigr = null;
		try {
			oldLogConfigr = logService.getLogConfiguration(Thread.currentThread());
			logService.unregister(Thread.currentThread());
			logService.register(operatorLogConfig);
						
			log.info(createRSOperatorStr(registeredService) + " STARTED.");
		} catch (Exception e) {			
		} finally {
			if (oldLogConfigr != null) {
				logService.unregister();
				for (LogConfiguration config : oldLogConfigr) {
					logService.register(config);
				}
			} else {
				logService.unregister();
			}
		}
	}
	
	/**
	 * 服务停止操作日志
	 * 
	 * @param registeredService
	 */
	private void stopRSOperatorLog(RegisteredService registeredService) {
		List<LogConfiguration> oldLogConfigr = null;
		try {
			oldLogConfigr = logService.getLogConfiguration(Thread.currentThread());
			logService.unregister(Thread.currentThread());
			logService.register(operatorLogConfig);
			
			OperatorLog olog = (OperatorLog) registeredService.getAttributes()
					.getAttribute(FrameworkConstants.RSOPERATOR_LOG);
			if (olog == null) {
				olog = new OperatorLog("admin", "stop", TimeUtil
						.getCurrentTime());
			}
			
			log.info(createRSOperatorStr(registeredService) + " STOPPED. "
					+ "[stopped by '" + olog.getUsername()+ "' use '"
					+ olog.getCommand() + "' command at '" + olog.getTime() + "']");
		} catch (Exception e) {			
		} finally {
			if (oldLogConfigr != null) {
				logService.unregister();
				for (LogConfiguration config : oldLogConfigr) {
					logService.register(config);
				}
			} else {
				logService.unregister();
			}
		}
	}
	
	/**
	 * 启动指定的服务
	 * 
	 * @param registeredService
	 */
	private void startRegisterService(RegisteredService registeredService) throws Throwable {
		List<LogConfiguration> oldLogConfigr = null;
		boolean rsStarted = false;
		List<Endpoint> putEndpoints = new ArrayList<Endpoint>();
				
		try {
			oldLogConfigr = logService.getLogConfiguration(Thread.currentThread());
			logService.unregister(Thread.currentThread());
			logService.register(registeredService.getLogConfiguration());
			// 启动			
			RegisteredServiceContextImpl serviceContext = registeredServiceContext.copyFrom(registeredService, this.allRSListeners);
			registeredService.start(serviceContext);
			rsStarted = true; // 已经启动
			
			Collection<Endpoint> endpoints = registeredService.getEndpoints();			
			for (Endpoint endpoint : endpoints) {
				synchronized (services) {
					String idStr = String.valueOf(endpoint.getId());
					
					Map<Endpoint, RegisteredService> rss = services.get(idStr);					
					if (rss == null) {
						rss = new ConcurrentHashMap<Endpoint, RegisteredService>();
						services.put(idStr, rss);
					}
					
					if (rss.get(endpoint) != null) {
						log.error("the service for the endpoint " + endpoint + " already in use.");
						
						throw new RuntimeException("the service for the endpoint " + endpoint + " already in use.");
					}
					
					rss.put(endpoint, registeredService);
					putEndpoints.add(endpoint);
				}
			}
			// listeners
			this.allRSListeners.put(registeredService, serviceContext.getServiceListeners());
		} catch (Throwable e) {
			if (this.stateManage != null) {
				this.stateManage.updateState(registeredService.getBundleContext().getBundle().getBundleId(), 
						ContextState.INTERRUPTED, "Start RegisteredService Exception: " + registeredService, e);
			}
			log.error("Start RegisteredService Exception: " + registeredService, e);
						
			// 回滚
			if (rsStarted) {
				try {
				    registeredService.stop(registeredServiceContext.copyFrom(registeredService, this.allRSListeners));
				} catch (Throwable t) {					
				}
			}
			
			for (Endpoint ep : putEndpoints) {
				synchronized (services) {
					Map<Endpoint, RegisteredService> rss = services.get(String.valueOf(ep.getId()));
					if (rss != null) {
						rss.remove(ep);
					}
				}
			}
			
			this.allRSListeners.remove(registeredService);
			
			throw e;
		} finally {
			if (oldLogConfigr != null) {
				logService.unregister();
				for (LogConfiguration config : oldLogConfigr) {
					logService.register(config);
				}
			} else {
				logService.unregister();
			}
		}
	}
	
	/**
	 * 停止指定的服务
	 * 
	 * @param registeredService
	 */
	private void stopRegisterService(RegisteredService registeredService) {
		List<LogConfiguration> oldLogConfigr = null;
		try {
			oldLogConfigr = logService.getLogConfiguration(Thread.currentThread());
			logService.unregister(Thread.currentThread());
			logService.register(registeredService.getLogConfiguration());
			// 停止
			try {
			    registeredService.stop(registeredService.getRegisteredServiceContext());
			} catch (Throwable t) {				
			}
			
			String startTime = (String)registeredService.getAttributes().removeAttribute(FrameworkConstants.RS_ATTR_STARTTIME);
			if (StringUtil.trimWhiteToNull(startTime) == null) {
				return;
			}
			Collection<Endpoint> endpoints = registeredService.getEndpoints();						
			for (Endpoint endpoint : endpoints) {
				synchronized (services) {
					Map<Endpoint, RegisteredService> rss = services.get(String.valueOf(endpoint.getId()));
					if (rss != null) {
						rss.remove(endpoint);
					}
				}
			}
			this.allRSListeners.remove(registeredService);
		} catch (Throwable e) {
            log.error("Stop RegisteredService Exception: " + registeredService, e);	
            if (this.stateManage != null) {
            	this.stateManage.updateState(registeredService.getBundleContext().getBundle().getBundleId(), 
    					ContextState.INTERRUPTED, "Stop RegisteredService Exception: " + registeredService, e);
            }                        
		} finally {
			if (oldLogConfigr != null) {
				logService.unregister();
				for (LogConfiguration config : oldLogConfigr) {
					logService.register(config);
				}
			} else {
				logService.unregister();
			}
		}
	}
	
	/**
	 * 获取指定endpoint的服务
	 * 
	 */
	public RegisteredService getRegisteredService(Endpoint endpoint) {
		RegisteredService rs = null;
		Map<Endpoint, RegisteredService> rss = services.get(String.valueOf(endpoint.getId()));		
		if (rss != null) {
			rs = rss.get(endpoint);
			
			/*find the attribute value=* entry*/
			if (rs == null) {				
				for (Endpoint p : rss.keySet()) {					
					if (p.getId() == endpoint.getId() && p.atttibuesEqual(endpoint)) {						
						return rss.get(p);
					}
				}
			}
		}
		
		return rs;
	}
	
	/**
	 * 指定接口ID的服务
	 * 
	 * @param interfaceId
	 * @return
	 */
	public Collection<RegisteredService> getRegisteredServices(String interfaceId) {
		Collection<RegisteredService> rsList = Collections
                        .synchronizedSet(new HashSet<RegisteredService>());
				
		Collection<RegisteredService> rss = getRegisteredServices();
		if (rss != null) {
			for (RegisteredService rs : rss) {
				if (interfaceId.equals(rs.getId())) {
					rsList.add(rs);
				}
			}
		}
		
		return rsList;
	}
	
	/**
	 * 指定bundle ID的服务
	 * 
	 * @param interfaceId
	 * @return
	 */
	public RegisteredService getRegisteredService(long controlId) {
		Collection<RegisteredService> rss = getRegisteredServices();
		if (rss != null) {
			for (RegisteredService rs : rss) {
				if (controlId == rs.getBundleContext().getBundle().getBundleId()) {
					return rs;
				}
			}
		}
		
		return null;
	}
	
	public Collection<RegisteredService> getRegisteredServices() {
		Collection<Map<Endpoint, RegisteredService>> crss = services.values();
		Collection<RegisteredService> rscollection = Collections
		                    .synchronizedSet(new HashSet<RegisteredService>());
		
		for (Iterator<Map<Endpoint, RegisteredService>> it = crss.iterator(); it.hasNext();) {
			Map<Endpoint, RegisteredService> rss = it.next();
			
			rscollection.addAll(rss.values());
		}
		
		return rscollection;
	}
	
	public void setBundleContext(BundleContext context) {
	    this.context = context;
	}
    
	public Collection<RegisteredService> getRegisteredServices(long id) {
        Map<Endpoint, RegisteredService> rss = services.get(String.valueOf(id));
		
		if (rss != null) {
			return Collections
            .synchronizedSet(new HashSet<RegisteredService>(rss.values()));
		}
		
		return null;
	}
	
	public void setChannel(Channel channel) {
		this.channel = channel;
	}

	public void setLogService(LogService logService) {
		this.logService = logService;
	}

	public void setOperatorLogConfig(LogConfiguration operatorLogConfig) {
		this.operatorLogConfig = operatorLogConfig;
	}
}
